package com.cheer.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.math.MathUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.poi.excel.ExcelReader;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cheer.dao.ApplicantDao;
import com.cheer.dao.OrganizationDao;
import com.cheer.dao.StandingBookReviewDao;
import com.cheer.dto.*;
import com.cheer.entity.Applicant;
import com.cheer.entity.Organization;
import com.cheer.enums.OrgTypeEnum;
import com.cheer.enums.RoleEnum;
import com.cheer.exception.ServiceException;
import com.cheer.service.AdminService;
import com.cheer.service.OrganizationService;
import com.cheer.util.ExcelUtil;
import com.cheer.vo.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrganizationServiceImpl extends ServiceImpl<OrganizationDao, Organization> implements OrganizationService {

    @Autowired
    private OrganizationDao organizationDao;

    @Autowired
    private ApplicantDao applicantDao;

    @Autowired
    private StandingBookReviewDao standingBookReviewDao;

    @Autowired
    private AdminService adminService;

    @Override
    public List<OrganizationTreeVO> listJoinOrganizations() {
        List<Organization> organizations = organizationDao.listAll();
        organizations = organizations.stream()
                .filter(org -> org.getLevel() >= 3 && org.getOrgType() == OrgTypeEnum.AFFAIR.getCode())
                .collect(Collectors.toList());
        return listByTree(organizations);
    }

    @Override
    public List<OrganizationTreeVO> listRegisteredOrganizations() {
        List<Organization> organizations = organizationDao.listAll();
        organizations = organizations.stream()
                .filter(org -> org.getOrgRole() != RoleEnum.SUPER_ADMIN.getCode())
                .collect(Collectors.toList());
        return listByTree(organizations);
    }

    @Override
    public void delete(Long orgId) {
        if (CollectionUtils.isNotEmpty(organizationDao.listByParentOrgId(orgId))) {
            throw new ServiceException("当前机构存在下级机构，无法删除");
        }
        if (CollectionUtils.isNotEmpty(applicantDao.listByOrgId(orgId))) {
            throw new ServiceException("当前机构存在申报集体，无法删除");
        }
        if (CollectionUtils.isNotEmpty(standingBookReviewDao.listByOrgId(orgId))) {
            throw new ServiceException("当前机构存在审核流程，无法删除");
        }
        organizationDao.deleteById(orgId);
    }

    @Override
    public void upload(MultipartFile file) {
        // 读取文件
        try (ExcelReader reader = cn.hutool.poi.excel.ExcelUtil.getReader(file.getInputStream())) {
            reader.setHeaderAlias(OrgImportDTO.getHeaderAlias());
            List<OrgImportDTO> orgs = reader.read(0, 1, OrgImportDTO.class);
            long parentId = 4L;
            for (OrgImportDTO org : orgs) {
                String city = StringUtils.trimToNull(org.getCity());
                String region = StringUtils.trimToNull(org.getRegion());
                if (city != null) {
                    parentId = 4L;
                    OrganizationAddDTO organizationAddDTO = new OrganizationAddDTO();
                    organizationAddDTO.setParentOrgId(parentId);
                    organizationAddDTO.setOrgName(city);
                    parentId = add(organizationAddDTO);
                }
                if (region != null) {
                    OrganizationAddDTO organizationAddDTO = new OrganizationAddDTO();
                    organizationAddDTO.setParentOrgId(parentId);
                    organizationAddDTO.setOrgName(region);
                    add(organizationAddDTO);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public void uploadOrgWithManager(MultipartFile file, Long pId) {
        try(ExcelReader reader = cn.hutool.poi.excel.ExcelUtil.getReader(file.getInputStream())){

            reader.setHeaderAlias(OrgManagerImportDTO.getHeaderAlias());
            List<OrgManagerImportDTO> orgs = reader.read(1, 2, OrgManagerImportDTO.class);
            for (OrgManagerImportDTO org : orgs) {
                // 添加机构
                log.info("==== 机构名称{} =====",  org.getOrgName());
                log.info("==== 管理人名称{} ====",  org.getOrgName());
                OrganizationAddDTO organizationAddDTO = new OrganizationAddDTO();
                organizationAddDTO.setOrgName(org.getOrgName());
                organizationAddDTO.setParentOrgId(pId); // 管理人ID
                Long organizationId = add(organizationAddDTO);
                String account = PinyinUtil.getFirstLetter(org.getOrgName(), "");
                if(account.length() >=18){
                    account = account.substring(0, 18);
                }
                account += RandomUtil.randomNumbers(2);
                // 添加管理人
                AdminSaveDTO adminSaveDTO = new AdminSaveDTO();
                adminSaveDTO.setOrgId(organizationId);
                adminSaveDTO.setPhone(account);
                adminSaveDTO.setContactPerson(org.getOrgName());
                adminService.add(adminSaveDTO);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<Organization> listByTypeAndLevel(Integer code, Integer cityLevel) {

        return organizationDao.listByTypeAndLevel(code, cityLevel);
    }

    @Override
    public String getAllName(Organization organization) {

        String orgPath = organization.getOrgPath();
        String[] split = orgPath.split(",");
        List<String> name = new ArrayList<>();
        for (int i = 0; i <split.length; i++) {

            String id = split[i];
            if(StrUtil.isNotBlank(id)){
                Organization org = getById(id);
                name.add(org.getOrgName());
            }
        }
        String orgName = name.stream().collect(Collectors.joining("/"));
        return orgName + organization.getOrgName();
    }

    @Override
    public List<OrganizationTreeVO> referenceList(Long orgId) {

        Organization organization = organizationDao.selectById(orgId);
        if (organization == null) {
            return new ArrayList<>();
        }
        List<Integer> orgRoles = Lists.newArrayList(0,1,2);
        List<Organization> organizations = organizationDao.listByOrgPathAndRole(organization.getOrgPath(), orgRoles);
        if (organization.getOrgRole() == RoleEnum.SUPER_ADMIN.getCode()) {
            organizations = organizations.stream()
                    .filter(org -> org.getOrgRole() != RoleEnum.SUPER_ADMIN.getCode())
                    .collect(Collectors.toList());
        }
        return listByTree(organizations);
    }

    @Override
    public List<Organization> listByOrgRole(ArrayList<Integer> roles) {

        return organizationDao.listByOrgRole(roles);
    }

    @Override
    public List<OrganizationTreeVO> listByTree(Long orgId) {
        Organization organization = organizationDao.selectById(orgId);
        if (organization == null) {
            return new ArrayList<>();
        }
        List<Organization> organizations = organizationDao.listByOrgPath(organization.getOrgPath());
        if (organization.getOrgRole() == RoleEnum.SUPER_ADMIN.getCode()) {
            organizations = organizations.stream()
                    .filter(org -> org.getOrgRole() != RoleEnum.SUPER_ADMIN.getCode())
                    .collect(Collectors.toList());
        }
        return listByTree(organizations);
    }


    private List<OrganizationTreeVO> findChildren(Long orgId, List<Organization> organizations) {
        List<Organization> children = organizations.stream()
                .filter(organization -> Objects.equals(organization.getParentOrgId(), orgId))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(children)) {
            return null;
        }

        return children.stream()
                .map(organization -> buildOrganizationTreeVO(organization, organizations))
                .collect(Collectors.toList());
    }

    private OrganizationTreeVO buildOrganizationTreeVO(Organization organization, List<Organization> organizations) {
        OrganizationTreeVO organizationTreeVO = new OrganizationTreeVO();
        organizationTreeVO.setOrgId(organization.getId())
                .setOrgName(organization.getOrgName())
                .setOrgType(organization.getOrgType())
                .setChildren(findChildren(organization.getId(), organizations));
        return organizationTreeVO;
    }

    @Override
    public Page<OrganizationPageVO> getPage(Integer pageNum, Integer pageSize, Long orgId) {
        Organization organization = getById(orgId);
        if (organization == null) {
            return null;
        }

        PageHelper.startPage(pageNum, pageSize);
        String[] split = organization.getOrgPath().split(",");

        int childLevel = split.length;
        int currenttLevel = split.length + 1;

        List<OrganizationPageDTO> organizationDTOS = organizationDao.listPage(organization.getOrgPath(), childLevel, currenttLevel);
        PageInfo<OrganizationPageDTO> pageInfo = new PageInfo<>(organizationDTOS);

        List<Applicant> applicants = applicantDao.listByOrgPath(organization.getOrgPath());
        List<OrganizationPageVO> organizationVOS = organizationDTOS.stream()
                .map(org -> org.build(applicants))
                .collect(Collectors.toList());

        return new Page<OrganizationPageVO>().setPageNum(pageInfo.getPageNum())
                .setPageSize(pageInfo.getPageSize())
                .setPages(pageInfo.getPages())
                .setTotal(pageInfo.getTotal())
                .setContent(organizationVOS);
    }

    @Override
    public void download(Long orgId) {
        Organization organization = organizationDao.selectById(orgId);
        if (organization == null) {
            ExcelUtil.export(new ArrayList<>(), ApplicantExportVO.getHeaderAlias(), "组织机构信息.xlsx");
            return;
        }

        String[] split = organization.getOrgPath().split(",");
        int childLevel = split.length;
        int currenttLevel = split.length - 1;
        List<OrganizationPageDTO> organizationDTOS = organizationDao.listPage(organization.getOrgPath(), childLevel, currenttLevel);

        List<Applicant> applicants = applicantDao.listByOrgPath(organization.getOrgPath());
        List<OrganizationPageVO> organizationVOS = organizationDTOS.stream()
                .map(org -> org.build(applicants))
                .collect(Collectors.toList());

        List<OrganizationExportVO> organizationExportVOS = OrganizationExportVO.buildList(organizationVOS);
        ExcelUtil.export(organizationExportVOS, OrganizationExportVO.getHeaderAlias(), "组织机构信息.xlsx");
    }

    @Override
    @Transactional
    public Long add(OrganizationAddDTO organizationAddDTO) {
        Organization parentOrg = organizationDao.selectById(organizationAddDTO.getParentOrgId());
        if (parentOrg == null || parentOrg.getOrgRole() == RoleEnum.SUPER_ADMIN.getCode()) {
            throw new ServiceException("请选择有效的上级机构");
        }

        Organization organization = organizationAddDTO.build(parentOrg);
        organizationDao.insert(organization);

        Organization update = new Organization();
        update.setId(organization.getId());
        update.setOrgPath(organization.getOrgPath() + organization.getId() + ",");
        organizationDao.updateById(update);

        return organization.getId();
    }

    @Override
    public void update(OrganizationUpdateDTO organizationUpdateDTO) {
        Organization organization = new Organization();
        organization.setId(organizationUpdateDTO.getOrgId());
        organization.setOrgName(organizationUpdateDTO.getOrgName());
        organizationDao.updateById(organization);
    }

    private List<OrganizationTreeVO> listByTree(List<Organization> organizations) {
        if (CollectionUtils.isEmpty(organizations)) {
            return new ArrayList<>();
        }

        // 找出根节点，即层级最小的节点
        organizations.sort(Comparator.comparingInt(Organization::getLevel));
        int level = organizations.get(0).getLevel();
        List<Organization> roots = new ArrayList<>();
        for (Organization organization : organizations) {
            if (organization.getLevel() > level) {
                break;
            }
            roots.add(organization);
        }

        return roots.stream().map(organization ->
                OrganizationTreeVO.build(organization, listChildren(organization.getId(), organizations)))
                .collect(Collectors.toList());
    }

    private List<OrganizationTreeVO> listChildren(Long orgId, List<Organization> organizations) {
        List<Organization> children = organizations.stream()
                .filter(organization -> Objects.equals(organization.getParentOrgId(), orgId))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(children)) {
            return null;
        }
        return children.stream().map(organization ->
                OrganizationTreeVO.build(organization, listChildren(organization.getId(), organizations)))
                .collect(Collectors.toList());
    }
}
